package com.googlecode.archimedes.filegen.model;

import java.util.HashSet;
import java.util.Set;

/**
 * This represents the BusinessObject Entity for GenerateableTemplates
 * 
 * @author John Lema, Erik Gustavson
 * @version $Id: Entity.java 3078 2006-10-03 16:42:22 +0000 (Tue, 03 Oct 2006) erik $
 * @since Archimedes 1.0
 */
public class Entity extends AbstractType implements Abstractable {

	public Entity					extendedEntity		= null;
	public Set<Interface>			interfaces			= new HashSet<Interface>();
	public Set<String>				interfaceRefs		= new HashSet<String>();
	private boolean					abstractClass		= false;
	private Boolean					auditable			= null;
	private Boolean					evaluatable			= null;
	private String					tableName			= null;

	private static final boolean	AUDITABLE_DEFAULT	= false;					// EG 10-03-2006
	private static final boolean	EVALUATABLE_DEFAULT	= false;

	/**
	 * Returns true if there are any interfaces in the interface set
	 * 
	 * @return
	 */
	public boolean hasInterfaces() {
		return !getInterfaces().isEmpty();
	}

	/**
	 * @see com.tps.filegen.model.AbstractType#getMembers(boolean)
	 */
	@Override
	public Set<Member> getMembers(boolean includeInherited) {
		return addInterfaceMembers(super.getMembers(includeInherited));
	}

	/**
	 * @see com.tps.filegen.model.AbstractType#getRelationships(boolean)
	 */
	@Override
	public Set<Relationship> getRelationships(boolean includeInherited) {
		return addInterfaceRelationships(super.getRelationships(includeInherited));
	}

	/**
	 * Adds in the interface members to the passed in set of members
	 * 
	 * @param raw
	 * @return
	 */
	protected Set<Member> addInterfaceMembers(Set<Member> raw) {
		for (Interface anInterface : getInterfaces()) {
			raw.addAll(anInterface.getMembers());
		}

		return raw;
	}

	/**
	 * Adds in the interface relations to the passed in set of relations
	 * 
	 * @param raw
	 * @return
	 */
	protected Set<Relationship> addInterfaceRelationships(Set<Relationship> raw) {
		for (Interface anInterface : getInterfaces()) {
			raw.addAll(anInterface.getRelationships());
		}

		return raw;
	}

	/**
	 * @see com.tps.filegen.model.AbstractType#getExtendedType()
	 */
	@Override
	protected AbstractType getExtendedType() {
		return getExtendedEntity();
	}

	public boolean isExtendingEntity() {
		return getExtendsReference() != null;
	}

	/**
	 * Returns the extendedEntity.
	 * 
	 * @return Entity value of extendedEntity
	 */
	public Entity getExtendedEntity() {
		return extendedEntity;
	}

	/**
	 * Sets the extendedEntity
	 * 
	 * @param extendedEntity
	 *            The extendedEntity to set.
	 */
	public void setExtendedEntity(Entity extendedEntity) {
		this.extendedEntity = extendedEntity;
	}

	/**
	 * Returns the interfaceRefs.
	 * 
	 * @return Set<String> value of interfaceRefs
	 */
	public Set<String> getInterfaceRefs() {
		return interfaceRefs;
	}

	/**
	 * Sets the interfaceRefs
	 * 
	 * @param interfaceRefs
	 *            The interfaceRefs to set.
	 */
	public void setInterfaceRefs(Set<String> interfaceRefs) {
		this.interfaceRefs = interfaceRefs;
	}

	/**
	 * Returns the interfaces.
	 * 
	 * @return Set<Interface> value of interfaces
	 */
	public Set<Interface> getInterfaces() {
		return interfaces;
	}

	/**
	 * Sets the interfaces
	 * 
	 * @param interfaces
	 *            The interfaces to set.
	 */
	public void setInterfaces(Set<Interface> interfaces) {
		this.interfaces = interfaces;
	}

	/**
	 * Add an interface to this entity
	 * 
	 * @param anInterface
	 */
	public void addInterface(Interface anInterface) {
		this.getInterfaces().add(anInterface);
	}

	/**
	 * Adds an interface reference
	 * 
	 * @param interfaceRef
	 */
	public void addInterfaceRef(String interfaceRef) {
		this.getInterfaceRefs().add(interfaceRef);
	}

	/**
	 * Returns the abstractClass.
	 * 
	 * @return boolean value of abstractClass
	 */
	public boolean isAbstract() {
		return abstractClass;
	}

	/**
	 * Sets the abstractClass
	 * 
	 * @param abstractClass
	 *            The abstractClass to set.
	 */
	public void setAbstract(boolean abstractClass) {
		this.abstractClass = abstractClass;
	}

	/**
	 * Returns the auditable. First check if we are auditable. If we have a null value, check our parent class (if one exists) and use their auditable
	 * value. Finally, if our parent does not have the setting, use the default value.
	 * 
	 * @return boolean value of auditable
	 */
	public boolean isAuditable() {

		if (auditable != null) {
			return auditable.booleanValue();
		} else if (isExtendingEntity()) {
			return getExtendedEntity().isAuditable();
		}

		return AUDITABLE_DEFAULT;
	}

	/**
	 * Sets the auditable
	 * 
	 * @param auditable
	 *            The auditable to set.
	 */
	public void setAuditable(boolean auditable) {
		this.auditable = auditable;
	}

	/**
	 * Returns the evaluatable. First check if we are evaluatable. If we have a null value, check our parent class (if one exists) and use their
	 * evaluatable value. Finally, if our parent does not have the setting, use the default value.
	 * 
	 * @return boolean value of evaluatable
	 */
	public boolean isEvaluatable() {
		if (evaluatable != null) {
			return evaluatable.booleanValue();
		} else if (isExtendingEntity()) {
			return getExtendedEntity().isEvaluatable();
		}

		return EVALUATABLE_DEFAULT;
	}

	/**
	 * Sets the evaluatable
	 * 
	 * @param evaluatable
	 *            The evaluatable to set.
	 */
	public void setEvaluatable(boolean evaluatable) {
		this.evaluatable = evaluatable;
	}

	/**
	 * @param tableName
	 *            the tableName to set
	 */
	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	/**
	 * @return the tableName
	 */
	public String getTableName() {

		// if we have a fixed tablename, use that
		if (this.tableName != null) {
			return getTableName();
		}

		// look up our inheritence tree for the top-most parent with a valid tablename
		if (this.isExtendingEntity()) {
			return this.getExtendedEntity().getTableName();
		}

		// fall through -- either we or our ancestors do not have a tablename value -- use entityName converted to ENTITY_NAME case.
		return convertCamelToUpper(getEntityName());

	}
}